﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms;

namespace Noris.Tools.TraceVisualiser.Components
{
    // Část: tvorba štětců a per
    /// <summary>
	/// Třída pro zobrazování grafu některého typu v rámci gridu
	/// </summary>
	internal partial class GridGraphCls : DblGraphControl, ILeaveFocus
    {
        #region ZÁKLADNÍ NÁSTROJE = SOLID BRUSH, STANDARD PEN. Metody Get(), které vrací předem připravený opakovaně používaný nástroj, s modifikací barvy a stylu
        private Pen _GetPen(GridGraphPaletteType palette)
        {
            if (_StandardPen == null)
                _StandardPen = new Pen(Color.Black, 1F);

            // Společné nastavení:
            _StandardPen.DashStyle = DashStyle.Solid;
            _StandardPen.Width = 1F;

            // Povinně se musí nastavit Color:
            switch (palette)
            {
                case GridGraphPaletteType.RowHeaderGridTop:
                    _StandardPen.Color = SystemColors.ControlDarkDark;
                    break;
                case GridGraphPaletteType.RowHeaderGridBottom:
                    _StandardPen.Color = SystemColors.ControlLight;
                    break;
                case GridGraphPaletteType.VerticalGrid:
                    _StandardPen.Color = SystemColors.ControlDarkDark;
                    break;
                case GridGraphPaletteType.FrameSelection:
                    _StandardPen.Color = Color.FromArgb(64, Color.Black);
                    _StandardPen.Width = 2F;
                    break;
                case GridGraphPaletteType.FrameZoom:
                    _StandardPen.Color = Color.FromArgb(64, Color.Black);
                    _StandardPen.Width = 2F;
                    break;
                case GridGraphPaletteType.TreeLine:
                    _StandardPen.Color = Color.Black;
                    _StandardPen.DashStyle = DashStyle.Dot;
                    break;
                case GridGraphPaletteType.SelectedRowFrame:
                    _StandardPen.Color = Color.Brown;
                    _StandardPen.DashStyle = DashStyle.Dot;
                    break;
                case GridGraphPaletteType.FragmentOneLine:
                    _StandardPen.Color = Color.Black;
                    _StandardPen.DashStyle = DashStyle.Dot;
                    break;
                case GridGraphPaletteType.ElementCaptionText:
                    _StandardPen.Color = SystemColors.ControlText;
                    break;
                default:
                    _StandardPen.Color = Color.Black;
                    break;
            }
            return _StandardPen;
        }
        private Brush _GetBrush(GridGraphPaletteType palette)
        {
            if (_StandardSolidBrush == null) _StandardSolidBrush = new SolidBrush(Color.Gray);

            switch (palette)
            {
                case GridGraphPaletteType.HorizontalGridTop:
                    _StandardSolidBrush.Color = SystemColors.ControlDarkDark;
                    break;
                case GridGraphPaletteType.HorizontalGridBottom:
                    _StandardSolidBrush.Color = SystemColors.ControlLight;
                    break;
                case GridGraphPaletteType.FrameSelection:
                    _StandardSolidBrush.Color = Color.FromArgb(96, Color.LightBlue);
                    break;
                case GridGraphPaletteType.FrameZoom:
                    _StandardSolidBrush.Color = Color.FromArgb(24, Color.Yellow);
                    break;
                case GridGraphPaletteType.TimeTickPreferred:
                    _StandardSolidBrush.Color = SystemColors.ControlDarkDark;
                    break;
                case GridGraphPaletteType.TimeTickLargeTick:
                    _StandardSolidBrush.Color = SystemColors.ControlDarkDark;
                    break;
                case GridGraphPaletteType.TimeTickStandardTick:
                    _StandardSolidBrush.Color = SystemColors.ControlDarkDark;
                    break;
                case GridGraphPaletteType.TimeTickGroupDividerTick:
                    _StandardSolidBrush.Color = SystemColors.ControlDark;
                    break;
                case GridGraphPaletteType.ElementCaptionText:
                    _StandardSolidBrush.Color = SystemColors.ControlText;
                    break;
                case GridGraphPaletteType.TempElementWork:
                    if (_StandardHatchWorkBrush == null) _StandardHatchWorkBrush = new HatchBrush(HatchStyle.DottedGrid, Color.Black, Color.LightGray);
                    return _StandardHatchWorkBrush;
                case GridGraphPaletteType.TempElementError:
					if (_StandardHatchErrorBrush == null) _StandardHatchErrorBrush = new HatchBrush(HatchStyle.DottedDiamond, Color.Red, Color.LightGray);
					return _StandardHatchErrorBrush;
			    default:
                    _StandardSolidBrush.Color = SystemColors.Control;
                    break;
            }
            return _StandardSolidBrush;
        }
        private Pen _StandardPen;
        private SolidBrush _StandardSolidBrush;
        private HatchBrush _StandardHatchWorkBrush;
		private HatchBrush _StandardHatchErrorBrush;
		#endregion
        #region ROZŠÍŘENÝ BRUSH a FONT, GENERUJE SE VŽDY NOVÝ NA KONKRÉTNÍ POŽADAVEK A PROSTOR
        private Brush _CreateBrush(Rectangle cellArea, GridGraphPaletteType palette)
        {
            LinearGradientBrush lgb;
            ColorBlend cbl;
            switch (palette)
            {
                case GridGraphPaletteType.GridBack:
                    // Pozadí celého prvku, tj. prostor, kde nejsou data
                    return new SolidBrush(SystemColors.AppWorkspace);

                case GridGraphPaletteType.CellBackNormal:
                    // Pozadí normální buňky (není aktivní, není vybraná, není na ní myš)
                    return new SolidBrush(this.CellBackColor);

                case GridGraphPaletteType.CellBackSelected:
                    // Pozadí vybrané buňky (není aktivní, není na ní myš, je označena k dalšímu zpracování)
                    return new SolidBrush(Color.LightBlue);

                case GridGraphPaletteType.CellBackNormalMouse:
                    // Pozadí buňky s myší (není aktivní, není vybraná, je na ní myš)
                    return new SolidBrush(ColorShift(this.CellBackColor, -15));

                case GridGraphPaletteType.CellBackSelectedMouse:
                    // Pozadí vybrané buňky s myší (není aktivní)
                    return new SolidBrush(ColorShift(Color.LightBlue, -15));

                case GridGraphPaletteType.CellBackActiveWithFocus:
                    // Pozadí aktivní buňky s focusem
                    lgb = new LinearGradientBrush(cellArea, Color.White, Color.White, 90F);
                    cbl = new ColorBlend(4);
                    cbl.Positions = new float[] { 0.0F, 0.10F, 0.80F, 1F };
                    cbl.Colors = new Color[] { Color.DarkGreen, Color.LightGreen, Color.LightGreen, Color.White };
                    lgb.InterpolationColors = cbl;
                    return lgb;

                case GridGraphPaletteType.CellBackActiveNoFocus:
                    // Pozadí aktivní buňky bez focusu
                    lgb = new LinearGradientBrush(cellArea, Color.White, Color.White, 90F);
                    cbl = new ColorBlend(4);
                    cbl.Positions = new float[] { 0.0F, 0.10F, 0.80F, 1F };
                    Color grc = ColorShift(Color.LightGray, -5, +15, -5);
                    cbl.Colors = new Color[] { Color.Gray, grc, grc, Color.LightGray };
                    lgb.InterpolationColors = cbl;
                    return lgb;

                case GridGraphPaletteType.RowHeaderNormal:
                    // Hlavička řádku, bez myši:
                    lgb = new LinearGradientBrush(cellArea, SystemColors.ControlLightLight, SystemColors.ControlDark, 0F);
                    cbl = new ColorBlend(3);
                    cbl.Positions = new float[] { 0F, 0.7F, 1F };
                    cbl.Colors = new Color[] { SystemColors.ControlLight, SystemColors.Control, SystemColors.ControlDark };
                    lgb.InterpolationColors = cbl;
                    return lgb;

                case GridGraphPaletteType.RowHeaderMouse:
                    // Hlavička řádku, s myší:
                    lgb = new LinearGradientBrush(cellArea, SystemColors.ControlLightLight, SystemColors.ControlDark, 0F);
                    cbl = new ColorBlend(3);
                    cbl.Positions = new float[] { 0F, 0.7F, 1F };
                    Color shiftLight = ColorShift(SystemColors.ControlLight, 15, 15, 0);
                    cbl.Colors = new Color[] { shiftLight, shiftLight, Color.Yellow };
                    lgb.InterpolationColors = cbl;
                    return lgb;

            }
            return SystemBrushes.ControlLight;
        }
        /// <summary>
        /// Vytvoří štětec pro daný prostor, základní barvu a typ gradientu.
        /// </summary>
        /// <param name="cellArea"></param>
        /// <param name="color"></param>
        /// <param name="palette"></param>
        /// <returns></returns>
        private Brush _CreateBrush(Rectangle cellArea, Color color, GraphElementGradientType gradientType)
        {
			if (cellArea.Width <= 0 || cellArea.Height <= 0) return null;

            return _PaletteCreateBrushElementGraphGantt(cellArea, color, gradientType);
        }
        private Font _CreateFont(GridGraphPaletteType palette)
        {
            switch (palette)
            {
                case GridGraphPaletteType.ElementCaptionText:
                    return new Font(SystemFonts.DefaultFont, FontStyle.Regular);
            }
            return new Font(SystemFonts.DefaultFont, FontStyle.Regular);
        }
        #endregion
        #region GENERÁTORY GRAFICKÝCH NÁSTROJŮ
        /// <summary>
        /// Vygeneruje Brush pro element grafu, typu Gantt, podle konstantní logiky, s proměnným zadáním barev a modifikátorů
        /// </summary>
        /// <param name="area">Prostor, pro který se má gradient vypočítat. 
        /// Gradient může být prostorově závislý (pak musí svoji prostorovou závislost vyplnit do out parametru repeatType).</param>
        /// <param name="color">Základní barva, je daná skinem pro daný vizuální typ položky, odvozeno z Aps.DataElementCls.ElementVisualType</param>
        /// <param name="gradientType">Typ gradientu = odpovídá modifikaci palety = aktuální stav elementu (běžný, pod myší, fixní, aktivně pohybovaný, selectovaný)</param>
        /// <returns>Brush pro danou situaci</returns>
        private Brush _PaletteCreateBrushElementGraphGantt(Rectangle area, Color color, GraphElementGradientType gradientType)
        {
            Color basicColor = color;        // Základní barva, střed objektu
            Color lightColor = basicColor;   // Světlejší barva, většinou bývá nahoře (kromě stavu _GraphElementGradientType.ActiveItemBack)
            Color darkColor = basicColor;    // Tmavší barva, většinou je dole
            Color mediumColor;
            Color edgeColor = basicColor;    // Přechodová barva, jen v ActiveItemBack gradientu

            LinearGradientBrush lgb;
            ColorBlend cbl;
            HatchBrush htb;
            switch (gradientType)
            {
                case GraphElementGradientType.Standard:
                    // Standardní gradient
                    basicColor = color;
                    darkColor = ComponentLibrary.ColorShift(basicColor, -48);
                    lightColor = ComponentLibrary.ColorShift(basicColor, 64);
                    cbl = new ColorBlend(6);
                    cbl.Positions = ComponentLibrary.GetColorBlendPosition(area.Height, new int[] { 0, 1, 5, -6, -2, 0 });
                    cbl.Colors = new Color[] { lightColor, lightColor, basicColor, basicColor, darkColor, darkColor };
                    lgb = new LinearGradientBrush(area, Color.LightGray, Color.Gray, 90F);
                    lgb.InterpolationColors = cbl;
                    return lgb;
                case GraphElementGradientType.Fixed:
                    // Conservative gradient
                    basicColor = ComponentLibrary.ColorShift(color, +64);
                    darkColor = ComponentLibrary.ColorShift(color, -32);
                    htb = new HatchBrush(HatchStyle.SmallCheckerBoard, basicColor, darkColor);
                    return htb;
                case GraphElementGradientType.OnMouse:
                    // OnMouse gradient
                    basicColor = ComponentLibrary.ColorShift(color, 16, 32, 32);
                    darkColor = ComponentLibrary.ColorShift(basicColor, -48);
                    lightColor = ComponentLibrary.ColorShift(basicColor, 32, 64, 64);
                    cbl = new ColorBlend(6);
                    cbl.Positions = ComponentLibrary.GetColorBlendPosition(area.Height, new int[] { 0, 1, 7, -8, -2, 0 });
                    cbl.Colors = new Color[] { lightColor, lightColor, basicColor, basicColor, darkColor, darkColor };
                    lgb = new LinearGradientBrush(area, Color.LightGray, Color.Gray, 90F);
                    lgb.InterpolationColors = cbl;
                    return lgb;
                case GraphElementGradientType.Selected:
                    // Selected gradient: má opačné pořadí barev (nahoře tmavý, dole světlý), čímž reprezentuje "dolů promáčknutý" stav:
                    basicColor = ComponentLibrary.ColorShift(color, +16);
                    basicColor = ComponentLibrary.ColorShift(color, 16, 64, 64);
                    mediumColor = ComponentLibrary.ColorShift(color, -24);
                    darkColor = ComponentLibrary.ColorShift(basicColor, -48);
                    lightColor = ComponentLibrary.ColorShift(basicColor, 64, 48, 64);
                    cbl = new ColorBlend(8);
                    cbl.Positions = ComponentLibrary.GetColorBlendPosition(area.Height, new int[] { 0, 1, 3, 9, -11, -6, -2, 0 });
                    cbl.Colors = new Color[] { darkColor, darkColor, mediumColor, basicColor, basicColor, mediumColor, lightColor, lightColor };
                    lgb = new LinearGradientBrush(area, Color.LightGray, Color.Gray, 90F);
                    lgb.InterpolationColors = cbl;
                    return lgb;


                // Selected gradient
                //basicColor = ComponentLibrary.ColorShift(color, +96);
                //darkColor = ComponentLibrary.ColorShift(color, +16);
                //htb = new HatchBrush(HatchStyle.DarkHorizontal, basicColor, darkColor);
                //return htb;
                case GraphElementGradientType.Active:
                    // Aktivní gradient: má opačné pořadí barev (nahoře tmavý, dole světlý), čímž reprezentuje "dolů promáčknutý" stav:
                    basicColor = ComponentLibrary.ColorShift(color, +16);
                    basicColor = ComponentLibrary.ColorShift(color, 16, 64, 64);
                    mediumColor = ComponentLibrary.ColorShift(color, -24);
                    darkColor = ComponentLibrary.ColorShift(basicColor, -48);
                    lightColor = ComponentLibrary.ColorShift(basicColor, 64, 48, 64);
                    cbl = new ColorBlend(8);
                    cbl.Positions = ComponentLibrary.GetColorBlendPosition(area.Height, new int[] { 0, 1, 3, 9, -11, -6, -2, 0 });
                    cbl.Colors = new Color[] { darkColor, darkColor, mediumColor, basicColor, basicColor, mediumColor, lightColor, lightColor };
                    lgb = new LinearGradientBrush(area, Color.LightGray, Color.Gray, 90F);
                    lgb.InterpolationColors = cbl;
                    return lgb;
            }
            // default:
            lgb = new LinearGradientBrush(area, Color.LightGray, Color.Gray, 90F);
            return lgb;
        }
        /// <summary>
        /// Vygeneruje Brush pro element grafu, typu Link, podle konstantní logiky, s proměnným zadáním barev a modifikátorů
        /// </summary>
        /// <param name="area">Prostor, pro který se má gradient vypočítat. 
        /// Gradient může být prostorově závislý (pak musí svoji prostorovou závislost vyplnit do out parametru repeatType).</param>
        /// <param name="color">Základní barva, je daná skinem pro daný vizuální typ položky, odvozeno z Aps.DataElementCls.ElementVisualType</param>
        /// <param name="gradientType">Typ gradientu = odpovídá modifikaci palety = aktuální stav elementu (běžný, pod myší, fixní, aktivně pohybovaný, selectovaný)</param>
        /// <returns>Brush pro danou situaci</returns>
        private Brush _PaletteCreateBrushElementGraphLink(Rectangle area, Color color, GraphElementGradientType gradientType)
        {
            Color basicColor = color;        // Základní barva, střed objektu
            Color lightColor = basicColor;   // Světlejší barva, většinou bývá nahoře (kromě stavu _GraphElementGradientType.ActiveItemBack)
            Color darkColor = basicColor;    // Tmavší barva, většinou je dole
            Color edgeColor = basicColor;    // Přechodová barva, jen v ActiveItemBack gradientu

            LinearGradientBrush lgb;
            ColorBlend cbl;
            HatchBrush htb;
            switch (gradientType)
            {
                case GraphElementGradientType.Standard:
                    // Standardní gradient
                    lightColor = ComponentLibrary.ColorShift(basicColor, 48);
                    darkColor = ComponentLibrary.ColorShift(basicColor, -64);
                    return new LinearGradientBrush(area, lightColor, darkColor, 90F);
                case GraphElementGradientType.Fixed:
                    // Conservative gradient
                    basicColor = ComponentLibrary.ColorShift(color, +64);
                    darkColor = ComponentLibrary.ColorShift(color, -32);
                    htb = new HatchBrush(HatchStyle.SmallCheckerBoard, basicColor, darkColor);
                    return htb;
                case GraphElementGradientType.OnMouse:
                    // OnMouse gradient
                    lightColor = ComponentLibrary.ColorShift(basicColor, 80);
                    darkColor = ComponentLibrary.ColorShift(basicColor, -32, 0, -32);
                    return new LinearGradientBrush(area, lightColor, darkColor, 90F);
                case GraphElementGradientType.Selected:
                    // Selected gradient
                    lightColor = ComponentLibrary.ColorShift(basicColor, 32, 96, 32);
                    darkColor = ComponentLibrary.ColorShift(basicColor, -32, 0, -32);
                    lgb = new LinearGradientBrush(area, lightColor, darkColor, 90F);
                    lgb.SetSigmaBellShape(0.667F);
                    return lgb;
                case GraphElementGradientType.Active:
                    // Aktivní gradient: má opačné pořadí barev (nahoře tmavý, dole světlý), čímž reprezentuje "dolů promáčknutý" stav:
                    darkColor = ComponentLibrary.ColorShift(basicColor, -32);
                    lightColor = ComponentLibrary.ColorShift(basicColor, 64);
                    return new LinearGradientBrush(area, darkColor, lightColor, 90F);
            }
            // default:
            darkColor = ComponentLibrary.ColorShift(basicColor, -48);
            lightColor = ComponentLibrary.ColorShift(basicColor, 64);
            return new LinearGradientBrush(area, lightColor, darkColor, 90F);
        }
        #endregion
    }
    /// <summary>
    /// Modifikace gradientů pro tvorbu Brush pro kreslení GraphElement.
    /// Brushe pro tento objekt jsou generovány obdobnou technikou v metodě this._PaletteCreateBrushElementGraphGantt(...),
    /// posloupnost barev se může lišit podle stavu objektu, a je specifikována touto hodnotou.
    /// </summary>
    public enum GraphElementGradientType
    {
        /// <summary>Standardní gradient, pohyblivé elementy (hodnota = 0, nic se nepřičítá)</summary>
        Standard = 0,
        /// <summary>Standardní gradient, nepohyblivé elementy</summary>
        Fixed,
        /// <summary>Gradient za situace, kdy je nad elementem myš - a nic nedělá, jen číhá...</summary>
        OnMouse,
        /// <summary>Gradient za situace, kdy je element zmáčknut myší a mění se jeho pozice nebo šířka</summary>
        Active,
        /// <summary>Gradient za situace, kdy je element vybrán</summary>
        Selected
    }
}
